#!/usr/bin/env python
"""
Simple example for an OpenID consumer.

Once you understand this example you'll know the basics of OpenID
and using the Python OpenID library. You can then move on to more
robust examples, and integrating OpenID into your application.
"""

from Cookie import SimpleCookie
import cgi, urlparse, cgitb, sys

from selector import Selector
from paste.request import parse_formvars
from paste.httpexceptions import *
from wsgiappclient.utils import get_base_url

def quoteattr(s):
    qs = cgi.escape(s, 1)
    return '"%s"' % (qs,)

import openid
from openid.store import filestore
from openid.consumer import consumer
from openid.oidutil import appendArgs

from openid.store import memstore

from openid.cryptutil import randomString
from openid.fetchers import setDefaultFetcher, Urllib2Fetcher
from openid import sreg


class OpenIDRequestMiddleware(object):
    """WSGI middleware that knows how to verify an OpenID identity."""

    def __init__(self, *args, **kw):
        self.sess_key = 'wsgiappclient.openid.auth'
        self.app_conf = kw
        self.s = Selector()
        self.s.add('', GET=self.index, POST=self.authenticate)
        self.s.add('/verified', GET=self.verified, POST=self.verified)

    def get_consumer(self, sess):
        return consumer.Consumer(sess, filestore.FileOpenIDStore('open_id_store'))

    def __call__(self, environ, start_response):
        print "In open id call"
        return self.s(environ, start_response)

    def index(self, environ, start_response):
        start_response('200 OK', [('content-type', 'text/html')])
        return ["""<html>
        <head>
          <title>OpenID Login</title>
        </head>
        <body>
          <div class="error" style="color: red">%s</div>
          <form action="." method="post">
            <input type="text" name="openid_url" />
            <input type="submit" name="submit" value="login" />
          </form>
        </body
        </html>""" % environ.get('openid.error', '')]

    def authenticate(self, environ, start_response):
        post = parse_formvars(environ)
        sess = environ['beaker.session']
        if not sess.get(self.sess_key):
            sess[self.sess_key] = {}
        if not post.get('openid_url'):
            raise HTTPBadRequest("need openid_url")

        consumer = self.get_consumer(sess[self.sess_key])
        try:
            request = consumer.begin(post['openid_url'])
        except Exception, exc:
            error_string = 'Error in discovery: %s' % (cgi.escape(str(exc[0])))
            environ['openid.error'] = error_string
            return self.index(environ, start_response)
        if request is None:
            error_string = 'No OpenID services found for <code>%s</code>' % (cgi.escape(post['openid_url']))
            environ['openid.error'] = error_string
            return self.index(environ, start_response)

        sreg_request = sreg.SRegRequest(required=['nickname'], optional=['fullname', 'email'])
        request.addExtension(sreg_request)
        return_to = urlparse.urljoin(get_base_url(environ), 'verified')
        trusted_root = self.app_conf['trusted_root']

        if request.shouldSendRedirect():
            redirect_url = request.redirectURL(trusted_root, return_to, immediate=True)
            sess[self.sess_key]['token'] = auth_req.token
            sess[self.sess_key]['trusted_root'] = trusted_root
            sess.save()
            start_response('302 Found',
                           [ ('location', redirect_url),
                             ('content-type', 'text/html') ]
            )
            return ['<html><head><title>redirect..</title></head>',
                    '<body>Redirecting to',
                    '<a href="%s">%s</a></body></html>' % (redirect_url, redirect_url) ]
        else:
            form_html = request.formMarkup(
                trusted_root, return_to,
                form_tag_attrs={'id':'openid_message'},
                immediate=True
            )
            # environ['openid.error'] = "no url provided"
            response = """\
            <html><head><title>OpenID transaction in progress</title></head>
            <body onload='document.getElementById("%s").submit()'>
            %s
            </body></html>
            """%('openid_message', form_html)
            start_response('200 OK', [('content-type', 'text/html')])
            return [response]

    def verified(self, environ, start_response):
        post = parse_formvars(environ)
        sess = environ['beaker.session']
        consumer = self.get_consumer()

        info = consumer.complete(post)
        if info.status == consumer.FAILURE and info.identity_url:
            fmt = "Verification of %s failed: %s"
            message = fmt % (cgi.escape(info.identity_url), info.message)
        elif info.status == consumer.SUCCESS:
            fmt = "You have successfully verified %s as your identity."
            message = fmt % (cgi.escape(info.identity_url),)
            sreg_resp = sreg.SRegResponse.fromSuccessResponse(info)
            if info.endpoint.canonicalID:
                message += ("  This is an i-name, and its persistent ID is %s"
                            % (cgi.escape(info.endpoint.canonicalID),))
        elif info.status == consumer.CANCEL:
            message = 'Verification cancelled'
        elif info.status == consumer.SETUP_NEEDED:
            if info.setup_url:
                message = '<a href=%s>Setup needed</a>' % (
                    quoteattr(info.setup_url),)
            else:
                message = 'Setup needed'
        else:
            message = 'Verification failed.'
        start_response('200 OK', [('content-type', 'text/plain')])
        return [message]
            
